package cn.dujy.derby.db_tool;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 杜家源
 * @since 1.0.1
 */
//代码生成器
@Slf4j
@Component
public class GenerateMybatis {

    /**
     * 表名: TABLE_NAME
     */
    public static final String TABLE_NAME = "contest";

    /**
     * 包名：PACKAGE_NAME
     */
    public static final String PACKAGE_NAME = "cn.dujy.derby";

    /**
     * java资源路径
     */
    public static final String JAVA_PAHE = "/src/main/java";

    /**
     * 静态资源路径
     */
    public static final String RESOURCES_PAHE = "/src/main/resources";

    /**
     * 子模块
     */
    public static final String MODULE_NAME = "";

    /**
     * 父模块
     */
    public static final String PARENT_MODULE_NAME = "pretty_derby";

    /**
     * 包名路径：PARENT_PATH
     */
    public static final String PACKAGE_NAME_PATH = PACKAGE_NAME.replace(".", "/");

    /**
     * common_db 包：cn.dujy.mybatis
     */
    public static final String JAVA_DB_COMMON_ROOT_PACKAGE = "cn.dujy.mybatis";

    // 启动类
    public static void main(String[] args) {

        //一、构建 代码生成器 对象
        AutoGenerator autoGenerator = new AutoGenerator();

        //二、编写策略
        //1、设置数据源
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setUrl("jdbc:mysql://sh-cynosdbmysql-grp-d33py9g8.sql.tencentcdb.com:25295/pretty_derby?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false");
        dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
        dataSourceConfig.setDbType(DbType.MYSQL);
        dataSourceConfig.setUsername("root");
        dataSourceConfig.setPassword("dujy1024mysql!");
        autoGenerator.setDataSource(dataSourceConfig);

        //2、全局配置
        GlobalConfig globalConfig = new GlobalConfig();
        String property = System.getProperty("user.dir");//项目位置
        globalConfig.setOutputDir(isModules(property, JAVA_PAHE));//输出目录
        globalConfig.setAuthor("杜家源");//作者
        globalConfig.setOpen(false);//生成结束后是否打开文件
        globalConfig.setFileOverride(false);//是否覆盖已有文件
        globalConfig.setDateType(DateType.ONLY_DATE);//时间选择
        globalConfig.setIdType(IdType.ASSIGN_UUID);//id类型
        globalConfig.setSwagger2(true);//开启Swagger2
        autoGenerator.setGlobalConfig(globalConfig);

        //3、包的配置
        PackageConfig packageConfig = new PackageConfig();
        packageConfig.setParent(PACKAGE_NAME);
        packageConfig.setModuleName("");// 此模块是指：PACKAGE_NAME 下的模块。若此处有值，Service等包就会在其下
        packageConfig.setEntity("domain");
        packageConfig.setController("web.rest");
        packageConfig.setService("service");
        packageConfig.setMapper("mapper");
        packageConfig.setXml("mapper");
        autoGenerator.setPackageInfo(packageConfig);

        //4、实体类对应表 策略
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig.setInclude(TABLE_NAME); //表名
        strategyConfig.setNaming(NamingStrategy.underline_to_camel);// 下划线转驼峰命名
        strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);//下划线转驼峰命名
        strategyConfig.setEntityLombokModel(true);
        strategyConfig.setRestControllerStyle(true);
        strategyConfig.setSuperEntityClass(JAVA_DB_COMMON_ROOT_PACKAGE + ".domain.BaseDomain");
        strategyConfig.setSuperEntityColumns("id", "gmt_create", "gmt_modified", "created_user_id", "last_modified_user_id", "is_disable");
        //strategyConfig.setLogicDeleteFieldName("is_disable");// 设置逻辑删除字段名（不设置默认的逻辑删除字段）
        strategyConfig.setRestControllerStyle(true);//驼峰命名
        strategyConfig.setEntityTableFieldAnnotationEnable(true);
        // 设置自动填充
        TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);//自动填充
        TableFill gmtModified = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE);//自动填充
        ArrayList<TableFill> tableFills = new ArrayList<>();
        tableFills.add(gmtCreate);
        tableFills.add(gmtModified);
        strategyConfig.setTableFillList(tableFills);
        autoGenerator.setStrategy(strategyConfig);

        //5、自定义配置
        addCustomTemplate(autoGenerator);

        //6、执行
        autoGenerator.execute();
    }


    /**
     * 自定义配置
     *
     * @param autoGenerator
     */
    private static void addCustomTemplate(AutoGenerator autoGenerator) {

        //1、申明 InjectionConfig 对象，可以在 initMap 中加入 自定义模板需要的值
        InjectionConfig cfg = new InjectionConfig() {
            //加入 自定义模板 需要的参数
            @Override
            public void initMap() {
                //1、服务相关
                Map<String, Object> map = new HashMap<>();
                map.put("swaggerServiceTitle", MODULE_NAME != "" ? MODULE_NAME : PARENT_MODULE_NAME);

                //2、包路径相关
                HashMap<String, String> packageMap = new HashMap<>();
                packageMap.put("config", PACKAGE_NAME + ".config");
                packageMap.put("handler", PACKAGE_NAME + ".handler");
                packageMap.put("common_db", JAVA_DB_COMMON_ROOT_PACKAGE);
                map.put("package", packageMap);
                this.setMap(map);
            }
        };

        //2、自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();

        //3、指定自定义模板位置 和输出 路径
        ////自定义模板
        //focList.add(new FileOutConfig("模板文件path") {
        //    @Override
        //    public String outputFile(TableInfo tableInfo) {
        //        // 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！
        //        return 输出文件全路径path（xxx/xx/xx/xx.java）
        //    }
        //});


        // 处理：自定义文件保存的路径和文件模板
        HashMap<String, String> templateMap = defineFilePath();

        //批量处理
        templateMap.forEach((path, templatePath) -> {
            focList.add(new FileOutConfig(templatePath) {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    // 将路径中自定义的占位符 替换为 指定的值
                    if (path.contains("${entityName}")) {
                        return path.replace("${entityName}", tableInfo.getEntityName());
                    }
                    return path;
                }
            });
        });

        //4、去掉已有的模板
        autoGenerator.setTemplate(
                new TemplateConfig()
                        .setXml(null)
                        .setController(null)
                        .setService(null)
                        .setServiceImpl(null)
                        .setEntity(null)
        );

        //5、使用模板
        cfg.setFileOutConfigList(focList);
        autoGenerator.setCfg(cfg);
    }

    /**
     * 自定义文件保存的路径和文件模板
     *
     * @return
     */
    private static HashMap<String, String> defineFilePath() {

        // <生成文件的存储位置，模板文件的路径>
        HashMap<String, String> templateMap = new HashMap<>();

        //项目位置
        String property = System.getProperty("user.dir");
        // java文件前缀
        String JAVA_PATH_PREFIX = isModules(property, JAVA_PAHE) + "/" + PACKAGE_NAME_PATH;
        // 资源文件前缀，例如：mapper.xml
        String RESOURCES_PATH_PREFIX = isModules(property, RESOURCES_PAHE) + "/" + PACKAGE_NAME_PATH;

        // ① 自定义 controller.java 模板
        templateMap.put(
                JAVA_PATH_PREFIX + "/web/rest/${entityName}Controller" + StringPool.DOT_JAVA,
                "/templates/controller.java.vm"
        );

        // ②自定义 IService.java 模板
        templateMap.put(
                JAVA_PATH_PREFIX + "/service/I${entityName}Service" + StringPool.DOT_JAVA,
                "/templates/service.java.vm"
        );

        // ③自定义 serviceImpl.java 模板
        templateMap.put(
                JAVA_PATH_PREFIX + "/service/impl/${entityName}ServiceImpl" + StringPool.DOT_JAVA,
                "/templates/serviceImpl.java.vm"
        );

        // ④自定义 DTOMapper.java 模板
        templateMap.put(
                JAVA_PATH_PREFIX + "/service/mapper/${entityName}DTOMapper" + StringPool.DOT_JAVA,
                "/templates/dtoMapper.java.vm"
        );


        // ⑤自定义 dto.java 模板
        templateMap.put(
                JAVA_PATH_PREFIX + "/service/dto/${entityName}DTO" + StringPool.DOT_JAVA,
                "/templates/dto.java.vm"
        );

        // entityName
        templateMap.put(
                JAVA_PATH_PREFIX + "/domain/${entityName}" + StringPool.DOT_JAVA,
                "/templates/entity.java.vm"
        );


        // ⑥自定义 mapper.xml 模板
        templateMap.put(
                RESOURCES_PATH_PREFIX + "/mapper/${entityName}Mapper" + StringPool.DOT_XML,
                "/templates/mapper.xml.vm"
        );

        // ⑦自定义 mapper.java 模板
        templateMap.put(
                JAVA_PATH_PREFIX + "/mapper/${entityName}Mapper" + StringPool.DOT_JAVA,
                "/templates/mapper.java.vm"
        );

        // ⑧自定义 swagger2Config 模板
        templateMap.put(
                JAVA_PATH_PREFIX + "/config/Swagger2Config" + StringPool.DOT_JAVA,
                "/templates/config/Swagger2Config.java.vm"
        );

        // ⑨自定义 MyBatisPlusConfig 模板
        templateMap.put(
                JAVA_PATH_PREFIX + "/config/MyBatisPlusConfig" + StringPool.DOT_JAVA,
                "/templates/config/MyBatisPlusConfig.java.vm"
        );

        // ⑩自定义 MyMetaObjectHandler 模板
        templateMap.put(
                JAVA_PATH_PREFIX + "/handler/MyMetaObjectHandler" + StringPool.DOT_JAVA,
                "/templates/handler/MyMetaObjectHandler.java.vm"
        );

        // 自定义 ExceptionHandle 模板
        templateMap.put(
                JAVA_PATH_PREFIX + "/handler/ExceptionHandle" + StringPool.DOT_JAVA,
                "/templates/handler/ExceptionHandle.java.vm"
        );

        return templateMap;
    }

    /**
     * 判断 modules 是否存在
     *
     * @param propertyPath 1
     * @param subsequentPath 2
     * @return String
     */
    private static String isModules(String propertyPath, String subsequentPath) {

        boolean isSeparatorEnd = propertyPath.lastIndexOf("/") + 1 == propertyPath.length();// 存在
        boolean isSeparatorStart = subsequentPath.indexOf("/") == 0; // 存在

        // 模块服务存在时
        if (MODULE_NAME != "") {
            return propertyPath + (isSeparatorEnd ? "" : "/") + MODULE_NAME + (isSeparatorStart ? "" : "/") + subsequentPath;
        }

        // 模块服务不存在时
        if (isSeparatorEnd && isSeparatorStart) {
            return propertyPath + subsequentPath.substring(1, subsequentPath.length());
        } else if ((isSeparatorEnd && !isSeparatorStart) || (!isSeparatorEnd && isSeparatorStart)) {
            return propertyPath + subsequentPath;
        } else {
            return propertyPath + "/" + subsequentPath;
        }
    }
}



























